/*****************************************************************************
 *   Copyright (C) 2008 John Schember <john@nachtimwald.com>                 *
 *                                                                           *
 *   This file is part of niwbillmanager.                                    *
 *                                                                           *
 *   niwbillmanager is free software: you can redistribute it and/or         *
 *   modify it under the terms of the GNU General Public License as          *
 *   published by the Free Software Foundation, either version 3 of the      *
 *   License, or (at your option) any later version.                         *
 *                                                                           *
 *   niwbillmanager is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
 *   GNU General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with niwbillmanager. If not, see                                  *
 *   <http://www.gnu.org/licenses/>.                                         *
 *****************************************************************************/

#include <QFileInfo>
#include <QStringList>

#include "backendplaintext.h"

Q_EXPORT_PLUGIN2(backend_plaintext, BackendPlainText)

BackendPlainText::BackendPlainText()
{
    m_errorMessage = "";
    m_plainTextFile = 0;
    m_plainTextStream = 0;
}

BackendPlainText::~BackendPlainText()
{
    closeCollection();
}

bool BackendPlainText::openCollection(
    BackendOpenMode::BackendOpenModes openMode, const QString &location,
    const QString &username, const QString &loginname,
    const QString &password)
{
    // We can't open directories.
    if (QFileInfo(location).isDir()) {
        m_errorMessage = "Cannot open: is Directory.";
        return false;
    }

    if (m_plainTextFile) {
        delete m_plainTextFile;
    }
    if (m_plainTextStream) {
        delete m_plainTextStream;
    }

    m_plainTextFile = new QFile(location);

    // Try to open the file.
    if (openMode == BackendOpenMode::READ) {
        if (!m_plainTextFile->open(QIODevice::ReadOnly)) {
            closeCollection();
            m_errorMessage = "Cannot open: read permission required.";
            return false;
        }
    }
    else if (openMode == BackendOpenMode::WRITE) {
        if (!m_plainTextFile->open(QIODevice::WriteOnly)) {
            closeCollection();
            m_errorMessage = "Cannot open: write permission required.";
            return false;
        }
    }
    else {
        closeCollection();
        m_errorMessage
            = "Cannot open: unknown Open Mode. Neither Read or Write given.";
        return false;
    }

    // Open the stream for working with.
    m_plainTextStream = new QTextStream(m_plainTextFile);

    // Check the first line is a plain text collection or write the first line
    // saying it is.
    if (openMode == BackendOpenMode::READ) {
        if (!m_plainTextStream->seek(0)) {
            m_errorMessage = "Could not read from file: seek failed";
            return false;
        }
        if (m_plainTextStream->readLine() != getName()) {
            m_errorMessage = "Invalid bill collection";
            return false;
        }
    }
    // We already checked earlier to be sure the openMode is valid.
    else {
        m_plainTextFile->resize(0);
        *m_plainTextStream << getName() << endl;
    }

    return true;
}

bool BackendPlainText::isCollectionOpen()
{
    if (m_plainTextFile) {
        return m_plainTextFile->isOpen();
    }

    return false;
}

void BackendPlainText::closeCollection()
{
    if (m_plainTextFile) {
        m_plainTextFile->close();
        delete m_plainTextFile;
    }
    if (m_plainTextStream) {
        delete m_plainTextStream;
    }

    m_plainTextFile = 0;
    m_plainTextStream = 0;
}

bool BackendPlainText::canReadIncremental()
{
    return true;
}

bool BackendPlainText::readAllBillItems(QSet<BillItem> &billItems)
{
    if (startReadNextBillItem()) {
        while (hasMoreBillItems()) {
            BillItem billItem;

            if (!readNextBillItem(billItem)) {
                return false;
            }

            billItems.insert(billItem);
        }

        return true;
    }

    return false;
}

bool BackendPlainText::startReadNextBillItem()
{
    if (m_plainTextFile && m_plainTextFile) {
        if (!m_plainTextStream->seek(0)) {
            return false;
        }

        m_plainTextStream->readLine();
        return true;
    }

    return false;
}

bool BackendPlainText::hasMoreBillItems()
{
    if (m_plainTextStream) {
        if (!m_plainTextStream->atEnd()) {
            return true;
        }
    }

    return false;
}

bool BackendPlainText::readNextBillItem(BillItem &billItem)
{
    if (m_plainTextStream) {
        QString line;
        QStringList items;

        line = m_plainTextStream->readLine();
        items = line.split(";^;");

        // Number of items + 1. + 1 because split divides the string into parts
        // based on the split expression.
        if (items.size() != 13) {
            m_errorMessage = "Bill entry improperly encoded.";
            return false;
        }

        billItem.setAmountDue(items.at(0));
        billItem.setAutoPay(items.at(1)=="T"?true:false);
        billItem.setDateDue(QDate::fromString(items.at(2), Qt::ISODate));
        billItem.setId(items.at(3));
        billItem.setPayee(items.at(4));
        billItem.setPaymentLocation(items.at(5));
        billItem.setPaymentMethod(items.at(6));
        billItem.setPaymentRecurringPeriod(
            RecurringPeriodType::stringToRecurringPeriodType(items.at(7)));
        billItem.setPaid(items.at(8)=="T"?true:false);
        billItem.setName(items.at(9));
        billItem.setNotes(items.takeAt(10).replace(":n:", "\n").replace(":r:",
            "\r"));
        billItem.setTags(items.at(10).split(" ").toSet());

        return true;
    }

    return false;
}

bool BackendPlainText::saveAllBillItems(QSet<BillItem> billItems)
{
    if (m_plainTextStream) {
        if (!m_plainTextFile->resize(0)) {
            m_errorMessage = "File could not be written";
            return false;
        }

        m_plainTextStream->seek(0);
        *m_plainTextStream << getName() << endl;

        Q_FOREACH (BillItem billItem, billItems) {
            saveBillItem(billItem);
        }

        return true;
    }

    return false;
}

bool BackendPlainText::canSaveTransactional()
{
    return false;
}

bool BackendPlainText::canSaveAllIncremental()
{
    return true;
}

bool BackendPlainText::saveChange(Transaction transaction)
{
    // This is not available in this backend.
    return false;
}

bool BackendPlainText::saveBillItem(const BillItem &billItem)
{
    if (m_plainTextStream) {
        *m_plainTextStream
            << billItem.getAmountDue().replace(";^;", "").replace("\n",
                "").replace("\r", "") << ";^;"
            << (billItem.getAutoPay()?"T":"F") << ";^;"
            << billItem.getDateDue().toString(Qt::ISODate) << ";^;"
            << billItem.getId().replace(";^;", "").replace("\n",
                "").replace("\r", "") << ";^;"
            << billItem.getPayee().replace(";^;", "").replace("\n",
                "").replace("\r", "") << ";^;"
            << billItem.getPaymentLocation().replace(";^;",
                "").replace("\n", "").replace("\r", "") << ";^;"
            << billItem.getPaymentMethod().replace(";^;",
                "").replace("\n", "").replace("\r", "") << ";^;"
            << RecurringPeriodType::recurringPeriodTypeToString(
                billItem.getPaymentRecurringPeriod()) << ";^;"
            << (billItem.getPaid()?"T":"F") << ";^;"
            << billItem.getName().replace(";^;", "").replace("\n",
                "").replace("\r", "") << ";^;"
            << billItem.getNotes().replace(";^;", "").replace("\n",
                ":n:").replace("\r", ":r:") << ";^;"
            << BillItem::stringSetToString(billItem.getTags()
                ).replace(";^;", "").replace("\n", "").replace("\r",
                "") << ";^;"
            << endl;

        return true;
    }

    return false;
}

QString BackendPlainText::getLastErrorMessage()
{
    return m_errorMessage;
}

bool BackendPlainText::isRemote()
{
    return false;
}

QString BackendPlainText::getName()
{
    return "PlainText";
}

QString BackendPlainText::getDescription()
{
    return "Single bill per line plain text file.";
}

QString BackendPlainText::getVersion()
{
    return "1.0";
}

QString BackendPlainText::getDefaultFileExtenstion()
{
    return "txt";
}
